/* Copyright (C) 2008 Robin Debreuil -- Released under the BSD License */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using DDW.Vex;

namespace DDW.VexTo2DPhysics
{
    public class Body2D : IComparable
    {
        public string InstanceName;
        public string TypeName;
        public int Depth;
        public Rectangle Bounds;
        private List<Shape2D> Shapes = new List<Shape2D>();
        public Symbol2D Symbol;
        public List<Transform> Transforms;

        //public Body2D(string instanceName, string typeName, int depth) : this(instanceName, typeName, depth, null)
        //{
        //}
        public Body2D(string instanceName, string typeName, int depth, Rectangle bounds)
        {
            this.InstanceName = instanceName;
            this.TypeName = typeName;
            this.Depth = depth;
            this.Bounds = bounds;
        }

        public void SetSymbol(string name, string path)
        {
            this.Symbol = new Symbol2D(name, path);
        }
        public bool HasShapes()
        {
            return Shapes.Count > 0;
        }
        public void AddShapes(VexObject vo, IDefinition def, Instance orgInst)
        {
            if (def.Name == "circleShape")
            {
                Matrix m = orgInst.Transformations[0].Matrix;
                Point c = new Point(m.TranslateX, m.TranslateY);
                float r = m.ScaleX * 100 / 2;
                Shapes.Add(new CircleShape2D(def.Name, c, r));
            }
            else if (def is Symbol)
            {
                Matrix m = orgInst.Transformations[0].Matrix;
                AddShape(def.Name, (Symbol)def, m);
            }
            else if (def is Timeline)
            {
                foreach (Instance inst in ((Timeline)def).Instances)
                {
                    IDefinition def2 = vo.Definitions[inst.DefinitionId];
                    if (def2 is Symbol)
                    {
                        Matrix m = inst.Transformations[0].Matrix;
                        AddShape(def.Name, (Symbol)def2, m);
                    }
                }
            }
        }
        public void AddShape(string name, Symbol sy, Matrix m)
        {
            for (int i = 0; i < sy.Shapes.Count; i++)
            {
                if (sy.Shapes[i].ShapeData.Count > 2) // must have 3 point for triangle
                {
                    Shapes.Add(new PolygonShape2D(name, sy.Shapes[i], m));
                }
            }             
        }

        public virtual bool IsPointInside(Point p)
        {
            bool result = false;
            System.Drawing.Drawing2D.Matrix m = 
                this.Transforms[0].Matrix.GetDrawing2DMatrix();
            m.Invert();
            System.Drawing.PointF[] p2 = new System.Drawing.PointF[] { new System.Drawing.PointF(p.X, p.Y) };
            m.TransformPoints(p2);
            Point tp = new Point(p2[0].X, p2[0].Y);
            for (int i = 0; i < Shapes.Count; i++)
            {
                if (Shapes[i].IsPointInside(tp))
                {
                    result = true;
                    break;
                }
            }
            return result;
        }

        public void DumpInstance(StringWriter sw, Dictionary<string, string> dict)
        {
            MatrixComponents mc = this.Transforms[0].Matrix.GetMatrixComponents();
            Point p = new Point(mc.TranslateX, mc.TranslateY);
            float rot = (float)(mc.Rotation * Math.PI / 180);
            float sx = mc.ScaleX;
            float sy = mc.ScaleY;

            sw.Write("          {" +
                "instName:\"" + this.InstanceName + "\", " +
                "type:\"" + this.TypeName + "\", " + 
                "location:" +  p.ToString()
                );

            if (rot != 0)
            {
                sw.Write(", rotation:" + rot);
            }
            if (Math.Abs(sx - 1) > .01)
            {
                sw.Write(", scaleX:" + sx);
            }
            if (Math.Abs(sy - 1) > .01)
            {
                sw.Write(", scaleY:" + sy);
            }
            if (!Transforms[0].ColorTransform.IsIdentity())
            {
                sw.Write(", colorTransform:" + Transforms[0].ColorTransform.ToString());
            }

            if (dict != null)
            {
                foreach (string k in dict.Keys)
                {
                    sw.Write(", " + k + ":" + dict[k]);
                }
            }
            sw.Write("}");
        }
        public void DumpInstance(XmlWriter xw, Dictionary<string, string> dict)
        {
            MatrixComponents mc = this.Transforms[0].Matrix.GetMatrixComponents();
            Point p = new Point(mc.TranslateX, mc.TranslateY);
            float rot = (float)(mc.Rotation * Math.PI / 180);
            float sx = mc.ScaleX;
            float sy = mc.ScaleY;

            xw.WriteStartElement("V2DInstance");

            xw.WriteAttributeString("InstanceName", InstanceName);
            xw.WriteAttributeString("DefinitonName", TypeName);
            xw.WriteAttributeString("X", p.X.ToString());
            xw.WriteAttributeString("Y", p.Y.ToString());

            if (rot != 0)
            {
                xw.WriteAttributeString("Rotation", rot.ToString());
            }
            if (Math.Abs(sx - 1) > .01)
            {
                xw.WriteAttributeString("ScaleX", sx.ToString());
            }
            if (Math.Abs(sy - 1) > .01)
            {
                xw.WriteAttributeString("ScaleY", sy.ToString());
            }
            if (!Transforms[0].ColorTransform.IsIdentity())
            {
                //sw.Write(", colorTransform:" + Transforms[0].ColorTransform.ToString());
            }

            if (dict != null)
            {
                foreach (string k in dict.Keys)
                {
                    xw.WriteAttributeString(k, dict[k]);
                }
            }

            xw.WriteEndElement(); // V2DInstance
        }
        public void DumpShapes(StringWriter sw)
        {
            sw.WriteLine("          " + this.TypeName + ":");
            sw.WriteLine("          [");

            for (int i = 0; i < Shapes.Count; i++)
            {
                Shape2D sh = Shapes[i];
                sw.Write("            ");
                sh.Dump(sw);
                if (i < Shapes.Count - 1)
                {
                    sw.Write(",");
                }
                sw.WriteLine("");
            }
            sw.WriteLine("          ]");
        }
        public void DumpShapeData(StringWriter sw)
        {
            for (int i = 0; i < Shapes.Count; i++)
            {
                Shape2D sh = Shapes[i];
                sh.Dump(sw);
                if (i < Shapes.Count - 1)
                {
                    sw.Write(",");
                }
            }
        }
        public void DumpShapeData(XmlWriter xw)
        {
            for (int i = 0; i < Shapes.Count; i++)
            {
                Shape2D sh = Shapes[i];
                sh.Dump(xw);
            }
        }

        public int CompareTo(object o)
        {
            int result = 0;
            if (o is Body2D)
            {
                result = Depth.CompareTo(((Body2D)o).Depth);
            }
            return result;
        }
    }
}
